﻿using System;
using System.Collections.Generic;
using System.Linq;
using AbstractBugTracker;
using log4net;

namespace JiraRest
{
    public sealed class JiraBug : JiraIssue, IBug
    {
        private static readonly ILog s_Log = LogManager.GetLogger("Jira.JiraBug");

        private readonly JiraConfig m_JiraConfig;
        private readonly JiraConnection m_Connection;

        internal JiraBug(JiraConfig jiraConfig, JiraConnection connection, string key) : base(key, connection)
        {
            m_JiraConfig = jiraConfig;
            m_Connection = connection;
        }

        public Uri Uri
        {
            get { return new Uri(new Uri(m_Connection.JiraServer + "/browse/"), Key); }
        }
        
        public BugState State
        {
            get
            {
                string statusName = Status;
                if (m_JiraConfig.ResolvedStatusNames.Contains(statusName))
                {
                    string resolutionName = Resolution;
                    if (m_JiraConfig.FixedResolutionNames.Contains(resolutionName))
                    {
                        return BugState.BelievedFixed;
                    }
                }

                return BugState.Unfixed;
            }
        }

        public void Close()
        {
            ProgressWorkflowAction(m_JiraConfig.CloseActionName, new { resolution = m_JiraConfig.CloseResolutionName });
        }

        public void Reopen()
        {
            ProgressWorkflowAction(m_JiraConfig.ReopenActionName);
        }

        private void ProgressWorkflowAction(string workflowAction, object fieldsToUpdate = null)
        {
            string query = "issue/" + Key + "/transitions";
            string possibleTransitionsJson = m_Connection.Api(query);
            List<object> possibleTransitions = DynamicJsonConverter.Deserialize(possibleTransitionsJson).transitions;

            int chosenTransition = possibleTransitions.Cast<dynamic>().First(obj => obj.name == workflowAction).id;

            // Now actually perform the transition
            object action = new { transition = chosenTransition, fields = fieldsToUpdate };
            string actionJson = DynamicJsonConverter.Serialize(action);
            m_Connection.Api(query, actionJson);
             
            s_Log.InfoFormat("Completed {0} {1}", workflowAction, Key);
        }

        public long ReportCount
        {
            get
            {
                object reportCountValue = GetCustomFieldValue(m_JiraConfig.ReportCountFieldName);
                if (reportCountValue == null) return 0;
                return (long) ((decimal) reportCountValue);
            }
            set
            {
                SetCustomFieldValue(m_JiraConfig.ReportCountFieldName, value);
            }
        }

        public string AutomaticEmail
        {
            get
            {
                return this[m_JiraConfig.AutomaticEmailFieldName];
            }
        }

        public Version BuildFixedOn
        {
            get
            {
                string version = this[m_JiraConfig.BuildFixedOnFieldName];
                return ParseVersionOrNull(version);
            }
        }

        private static Version ParseVersionOrNull(string version)
        {
            try
            {
                return version == null ? null : new Version(version);
            }
            catch (ArgumentException)
            {
                return null;
            }
            catch (FormatException)
            {
                return null;
            }
            catch (OverflowException)
            {
                return null;
            }
        }

        public Version EarliestBuild
        {
            get
            {
                string version = this[m_JiraConfig.EarliestBuildSeenFieldName];
                return ParseVersionOrNull(version);
            }
            set
            {
                this[m_JiraConfig.EarliestBuildSeenFieldName] = value.ToString();
            }
        }

        public Version LatestBuild
        {
            get
            {
                string version = this[m_JiraConfig.LatestBuildSeenFieldName];
                return ParseVersionOrNull(version);
            }
            set
            {
                this[m_JiraConfig.LatestBuildSeenFieldName] = value.ToString();
            }
        }
    }
}
